package com.yangzb.flink.sql.sample.util;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * sql变量替换类
 */
@Slf4j
public class SqlVariableUtils {
    public static final String rgex = "&&(.*?)&&";

    //	&&NOW|-1|yyyyMMdd&&
//			&&END_OF_LAST_MONTH|-1D|yyyyMMdd&&
//			&&START_OF_LAST_MONTH|-1D|yyyyMMdd&&
//			&&END_OF_THIS_MONTH|-1M|yyyyMMdd&&
//			&&START_OF_THIS_MONTH|-1M|yyyyMMdd&&
    public static String replaceVariables(String sql, Map<String, String> otherOption) throws Exception {
        if (sql == null) {
            return null;
        }
        Pattern pattern = Pattern.compile(rgex);// 匹配的模式
        Matcher m = pattern.matcher(sql);

        while (m.find()) {
            int i = 1;
            String keyStr = m.group(i);
            log.info("待格式化的日期字符串是" + keyStr);
            String[] keyLines = keyStr.split("\\|", -1);

            String type = keyLines[0];
            if (type.equals("DATE")) {
                /**
                 * NOW 当前日期
                 * END_OF_LAST_MONTH 上月最后一天
                 * START_OF_LAST_MONTH 上月开始第一天
                 * END_OF_THIS_MONTH 本月最后一天
                 * START_OF_THIS_MONTH 本月开始第一天
                 * yyyyMMdd 写死的日期
                 * yyyy-MM-dd 写死的日期二号
                 */
                if (keyLines.length >= 4) {//最少要有四位
                    String dateStr = keyLines[1];//日期描述符`
                    String modify = keyLines[2];//日期计算符
                    String dateFmt = keyLines[3];//日期格式化符

                    //根据date获取需要格式化的起点日期时间
                    Date startDate = null;
                    if (dateStr.equals("NOW")) {//当前日期
                        startDate = new Date();
                    } else if (dateStr.equals("END_OF_LAST_MONTH")) {//上月最后一天
                        Calendar c = Calendar.getInstance();
                        //当前日期设置为指定日期
                        c.setTime(new Date());
                        //指定日期月份减去一
                        c.add(Calendar.MONTH, -1);
                        //指定日期月份减去一后的 最大天数
                        c.set(Calendar.DATE, c.getActualMaximum(Calendar.DATE));
                        //获取上给月最后一天的日期
                        startDate = c.getTime();
                    } else if (dateStr.equals("START_OF_LAST_MONTH")) {//上月第一天
                        Calendar c = Calendar.getInstance();
                        //当前日期设置为指定日期
                        c.setTime(new Date());
                        //指定日期月份减去一
                        c.add(Calendar.MONTH, -1);
                        //指定第一天
                        c.set(Calendar.DATE, 1);
                        //获取上给月最后一天的日期
                        startDate = c.getTime();
                    } else if (dateStr.equals("END_OF_THIS_MONTH")) {//本月最后一天
                        Calendar c = Calendar.getInstance();
                        //当前日期设置为指定日期
                        c.setTime(new Date());
                        c.set(Calendar.DATE, c.getActualMaximum(Calendar.DATE));
                        //获取上给月最后一天的日期
                        startDate = c.getTime();
                    } else if (dateStr.equals("START_OF_THIS_MONTH")) {//本月第一天
                        Calendar c = Calendar.getInstance();
                        //当前日期设置为指定日期
                        c.setTime(new Date());
                        c.set(Calendar.DATE, 1);
                        //获取上给月最后一天的日期
                        startDate = c.getTime();
                    } else {//写死的日期
                        if (dateStr.indexOf("-") != -1) {//如果格式是yyyy-MM-dd
                            startDate = new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
                        } else {
                            startDate = new SimpleDateFormat("yyyyMMdd").parse(dateStr);
                        }
                    }
                    log.info("处理后的日期是" + startDate);
                    //处理modify信息
                    int dateInfo = 0;
                    if (modify.equals("")) {
                        modify = "0D";
                    }
                    String lastWord = modify.substring(modify.length() - 1, modify.length());//取得最后一位,来判断计算范围
                    String modifyWord = null;
                    Integer modifyUnit = null;
                    if (lastWord.equals("D")) {
                        modifyWord = modify.substring(0, modify.length() - 1);
                        modifyUnit = Calendar.DATE;
                    } else if (lastWord.equals("M")) {
                        modifyWord = modify.substring(0, modify.length() - 1);
                        modifyUnit = Calendar.MONTH;
                    } else if (StringUtils.isNumeric(lastWord)) {
                        modifyWord = modify;
                        modifyUnit = Calendar.DATE;//默认日期
                    }

                    Calendar c = Calendar.getInstance();
                    c.setTime(startDate);
                    c.add(modifyUnit, Integer.parseInt(modifyWord));

                    String resultStr = new SimpleDateFormat(dateFmt).format(c.getTime());

                    sql = sql.replace("&&" + keyStr + "&&", resultStr);
                } else {
                    throw new Exception("请检查sql中的变量设置: &&" + keyStr + "&&");
                }

            } else if (type.equals("OTHER")) {//其他配置
                String key = keyLines[1];
                String val = "";
                if (otherOption != null) {

                    for (String otherKey : otherOption.keySet()) {
                        if (otherKey.equals(key)) {
                            val = otherOption.get(otherKey);
                            val = val == null ? "" : val;

                        }

                    }
                }
                sql = sql.replace("&&" + keyStr + "&&", val);
            }


            i++;
        }


        return sql;
    }

    public static List<String> replaceVariables(List<String> sqlList, Map<String, String> otherOptions) throws Exception {
        if (sqlList == null || sqlList.size() == 0) {
            return null;
        }
        List<String> newSqlList = new ArrayList<>();
        for (String sql : sqlList) {
            newSqlList.add(replaceVariables(sql, otherOptions));
        }

        return newSqlList;
    }
}
